﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;

namespace Share
{
    public class ICommonObject { };

    public class EventMgr : SingletonObject<EventMgr>
    {

        public delegate bool EventFunction(int ge, EventParam parameter);

        public struct EventNode
        {
            public EventFunction Function;

            public bool IsInvalid() => Function == null;

            public EventNode(EventFunction fun, bool bFromLua)
            {
                Function = fun;
            }

            public bool Trigger(int ge, EventParam parameter)
            {
                try
                {
                    if (Function != null)
                    {
                        return Function(ge, parameter);
                    }
                }
                catch (Exception ex)
                {
                    XKLog.LogError($"EventNode.Trigger failed: {ex.Message}");
                    throw new InvalidOperationException("Event trigger failed", ex);
                }
                return true;
            }

            public bool IsEqual(EventNode node) => Function == node.Function;
        }

        private readonly ConcurrentDictionary<int, List<EventNode>> eventMap = new ConcurrentDictionary<int, List<EventNode>>();
        private readonly ConcurrentQueue<EventData> dataList = new ConcurrentQueue<EventData>();
        private readonly ConcurrentDictionary<SmartTimer, EventData> m_DelayEvent = new ConcurrentDictionary<SmartTimer, EventData>();

        public void AddListener(int ge, EventFunction ef, bool bFromLua = false)
        {
            if (ef == null) throw new ArgumentNullException(nameof(ef));

            var list = eventMap.GetOrAdd(ge, _ => new List<EventNode>());
            lock (list)
            {
                if (!list.Any(node => node.IsEqual(new EventNode(ef, bFromLua))))
                    list.Add(new EventNode(ef, bFromLua));
            }
        }

        public void RemoveListener(int ge, EventFunction ef)
        {
            if (ef == null) return;

            if (eventMap.TryGetValue(ge, out var list))
            {
                lock (list)
                {
                    list.RemoveAll(node => node.IsEqual(new EventNode(ef, false)));
                }
            }
        }

        public struct EventData
        {
            public EventData(int ge, EventParam ep)
            {
                Event = ge;
                parameter = ep?.DeepClone(); // 确保深拷贝
            }

            public int Event;
            public EventParam parameter;
        }

        public void DoUpdate()
        {
            while (dataList.TryDequeue(out var ed))
            {
                TriggerEvent(ed.Event, ed.parameter);
            }


            var keys = m_DelayEvent.Keys.ToList(); // 获取当前所有键的副本，避免并发修改问题
            foreach (var key in keys)
            {
                if (m_DelayEvent.TryGetValue(key, out var item) && key.DoUpdate())
                {
                    try
                    {
                        TriggerEvent(item.Event, item.parameter); // 触发事件并捕获可能的异常
                    }
                    catch (Exception ex)
                    {
                        // 记录异常日志，但不中断整个更新逻辑
                        XKLog.LogError($"Error triggering delayed event {item.Event}: {ex.Message}");
                    }

                    // 移除已处理的延迟事件
                    m_DelayEvent.TryRemove(key, out _);
                }
            }
        }

        public void TriggerEvent(int ge, string key, int value)
        {
            var param = new EventParamCommon();
            param.AddData(key, value);
            TriggerEvent(ge, param);
        }
        /// <summary>
        /// 发送延迟消息，如果消息已经存在，就需要对数据进行合并，
        /// </summary>
        /// <param name="ge"></param>
        /// <param name="param"></param>
        /// <param name="fDelay"></param>
        /// <exception cref="ArgumentNullException"></exception>
        public void TriggerEventDelay(int ge, EventParam param, float fDelay = 0)
        {
            var data = new EventData(ge, param);
            if (fDelay <= 0)
            {
                // 检查 dataList 中是否已经存在相同的事件
                bool isMerged = false;
                foreach (var ed in dataList)
                {
                    if (ed.Event == ge)
                    {
                        if (ed.parameter != null && param != null && ed.parameter.Combin(param))
                        {
                            isMerged = true;
                            break;
                        }
                        // 如果新的事件参数不为空，旧参数不为空，就作为新的添加
                        else if (param != null && ed.parameter == null)
                        {
                            break;
                        }
                        isMerged = true;
                        break;
                    }
                }

                if (!isMerged)
                {
                    dataList.Enqueue(data); // 使用无锁队列
                }
            }
            else
            {
                var st = new SmartTimer();
                st.DoReset(fDelay);
                if (!m_DelayEvent.TryAdd(st, data))
                {
                    // 添加失败时的日志记录
                    XKLog.LogWarning("Failed to add event to m_DelayEvent.");
                }
            }
        }

        //直接触发消息

        public void TriggerEvent(int ge, EventParam parameter)
        {

            if (eventMap.TryGetValue(ge, out var list))
            {
                var validNodes = list.Where(node => !node.IsInvalid()).ToList(); // 提前过滤无效节点
                foreach (var node in validNodes)
                {
                    try
                    {
                        if (!node.Trigger(ge, parameter))
                            return; // 如果某个事件处理函数返回 false，则停止后续触发
                    }
                    catch (Exception ex)
                    {
                        XKLog.LogError($"Error triggering event {ge}: {ex.Message}");
                        // 记录错误日志，但继续处理后续事件
                    }
                }
            }
        }
    }
}